Security News
Weekly Downloads Now Available in npm Package Search Results
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.
Helmet is a middleware for Express applications that helps secure your apps by setting various HTTP headers. It's not a silver bullet, but it can help prevent some well-known web vulnerabilities by setting headers appropriately.
Content Security Policy
Sets the Content-Security-Policy header to help prevent cross-site scripting attacks and other cross-site injections.
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "https://trustedscripts.example.com"],
objectSrc: ["'none'"],
upgradeInsecureRequests: [],
}
}));
X-DNS-Prefetch-Control
Controls browser DNS prefetching, which can improve user privacy at the expense of performance.
app.use(helmet.dnsPrefetchControl({ allow: false }));
Expect-CT
Sets the Expect-CT header which allows sites to opt in to reporting and/or enforcement of Certificate Transparency requirements.
app.use(helmet.expectCt({
enforce: true,
maxAge: 86400
}));
X-Frame-Options
Sets the X-Frame-Options header to control whether the browser should be allowed to render a page in a <frame>, <iframe>, <embed>, or <object>.
app.use(helmet.frameguard({ action: 'deny' }));
X-Powered-By
Removes the X-Powered-By header to make it slightly harder for attackers to see what potentially vulnerable technology powers your site.
app.use(helmet.hidePoweredBy());
Strict-Transport-Security
Sets the Strict-Transport-Security header to enforce secure (HTTP over SSL/TLS) connections to the server.
app.use(helmet.hsts({
maxAge: 15552000,
includeSubDomains: true
}));
X-Download-Options
Sets X-Download-Options for IE8+ to prevent others from embedding your site in an iframe.
app.use(helmet.ieNoOpen());
X-Content-Type-Options
Sets the X-Content-Type-Options header to prevent browsers from MIME-sniffing a response away from the declared content-type.
app.use(helmet.noSniff());
Referrer Policy
Sets the Referrer-Policy header to control what information is sent along with the requests.
app.use(helmet.referrerPolicy({ policy: 'no-referrer' }));
X-XSS-Protection
Sets the X-XSS-Protection header to enable the Cross-site scripting (XSS) filter in most recent web browsers.
app.use(helmet.xssFilter());
Lusca is another security middleware for Express applications that offers a variety of security features such as CSRF protection, CSP, X-Frame options, and more. It is similar to Helmet but allows for more granular configuration of security policies.
CORS is a package for providing a Connect/Express middleware that can be used to enable CORS (Cross-Origin Resource Sharing) with various options. While Helmet focuses on securing your app from various web vulnerabilities, CORS specifically provides middleware to enable CORS and manage cross-origin requests.
Helmet is a series of middleware that help secure your Express/Connect apps. It's not a silver bullet, but it can help!
Helmet includes the following middleware:
crossdomain
(crossdomain.xml)csp
(Content Security Policy)hidePoweredBy
(remove X-Powered-By)hsts
(HTTP Strict Transport Security)ienoopen
(X-Download-Options for IE8+)nocache
(Cache-Control)nosniff
(X-Content-Type-Options)xframe
(X-Frame-Options)xssFilter
(X-XSS-Protection for IE8+ and Chrome)Helmet also includes a default configuration of the above middleware that can be dropped into your applications.
First, install it:
npm install helmet --save
To use a particular middleware application-wide, just use
it:
var helmet = require('helmet');
var app = express(); // or connect
app.use(helmet.xframe('deny'));
app.use(helmet.contentTypeOptions());
If you're using Express 3, make sure these middlewares are listed before app.router
.
If you just want to use the default-level policies, all you need to do is:
app.use(helmet());
Don't want all the defaults?
app.use(helmet({ xframe: false, hsts: false }));
app.use(helmet.xframe('sameorigin'));
For each of the middlewares, we'll talk about three things:
Let's get started.
Trying to prevent: Injecting anything unintended into our page. That could cause XSS vulnerabilities, unintended tracking, malicious frames, and more.
How to use Helmet to mitigate this: Set an appropriate Content Security Policy. If you want to learn how CSP works, check out the fantastic HTML5 Rocks guide and the Content Security Policy Reference.
Usage:
app.use(helmet.csp({
defaultSrc: ["'self'", 'default.com'],
scriptSrc: ['scripts.com'],
styleSrc: ['style.com'],
imgSrc: ['img.com'],
connectSrc: ['connect.com'],
fontSrc: ['font.com'],
objectSrc: ['object.com'],
mediaSrc: ['media.com'],
frameSrc: ['frame.com'],
sandbox: ['allow-forms', 'allow-scripts'],
reportUri: '/report-violation',
reportOnly: false, // set to true if you only want to report errors
setAllHeaders: false, // set to true if you want to set all headers
safari5: false // set to true if you want to force buggy CSP in Safari 5
}));
You can specify keys in a camel-cased fashion (imgSrc
) or dashed (img-src
); they are equivalent.
There are a lot of inconsistencies in how browsers implement CSP. Helmet sniffs the user-agent of the browser and sets the appropriate header and value for that browser. If no user-agent is matched, it will set all the headers with the 1.0 spec.
Note: If you're using the reportUri
feature and you're using csurf, you might have errors. Check this out for a workaround.
Limitations: CSP is often difficult to tune properly, as it's a whitelist and not a blacklist. It isn't supported on old browsers but is pretty well-supported on non-IE browsers nowadays.
Trying to prevent: Cross-site scripting attacks (XSS), a subset of the above.
How to use Helmet to mitigate this: The X-XSS-Protection
HTTP header is a basic protection against XSS. It was originally by Microsoft but Chrome has since adopted it as well. Helmet lets you use it easily:
app.use(helmet.xssFilter());
This sets the X-XSS-Protection
header. On modern browsers, it will set the value to 1; mode=block
. On old versions of Internet Explorer, this creates a vulnerability (see here and here), and so the header is set to 0
to disable it. To force the header on all versions of IE, add the option:
app.use(helmet.xssFilter({ setOnOldIE: true }));
// This has some security problems for old IE!
Limitations: This isn't anywhere near as thorough as CSP. It's only properly supported on IE9+ and Chrome; no other major browsers support it at this time. Old versions of IE support it in a buggy way, which we disable by default.
Trying to prevent: Your page being put in a <frame>
or <iframe>
without your consent. This helps to prevent things like clickjacking attacks.
How to use Helmet to mitigate this: The X-Frame
HTTP header restricts who can put your site in a frame. It has three modes: DENY
, SAMEORIGIN
, and ALLOW-FROM
. If your app does not need to be framed (and most don't) you can use the default DENY
. If your site can be in frames from the same origin, you can set it to SAMEORIGIN
. If you want to allow it from a specific URL, you can allow that with ALLOW-FROM
and a URL.
Usage:
// These are equivalent:
app.use(helmet.xframe());
app.use(helmet.xframe('deny'));
// Only let me be framed by people of the same origin:
app.use(helmet.xframe('sameorigin'));
// Allow from a specific host:
app.use(helmet.xframe('allow-from', 'http://example.com'));
Limitations: This has pretty good (but not 100%) browser support: IE8+, Opera 10.50+, Safari 4+, Chrome 4.1+, and Firefox 3.6.9+. It only prevents against a certain class of attack, but does so pretty well. It also prevents your site from being framed, which you might want for legitimate reasons.
Trying to prevent: Users viewing your site on HTTP instead of HTTPS. HTTP is pretty insecure.
How to use Helmet to mitigate this: This middleware adds the Strict-Transport-Security
header to the response. This tells browsers, "hey, only use HTTPS for the next period of time". (See the spec for more.)
This will set the Strict Transport Security header, telling browsers to visit by HTTPS for the next ninety days:
var ninetyDaysInMilliseconds = 7776000000;
app.use(helmet.hsts({ maxAge: ninetyDaysInMilliseconds }));
You can also include subdomains. If this is set on example.com, supported browsers will also use HTTPS on my-subdomain.example.com. Here's how you do that:
app.use(helmet.hsts({
maxAge: 123000,
includeSubdomains: true
}));
Chrome lets you submit your site for baked-into-Chrome HSTS by adding preload
to the header. You can add that with the following code, and then submit your site to the Chrome team at hstspreload.appspot.com.
app.use(helmet.hsts({
maxAge: 10886400000, // Must be at least 18 weeks to be approved by Google
includeSubdomains: true, // Must be enabled to be approved by Google
preload: true
}));
This'll be set if req.secure
is true, a boolean auto-populated by Express. If you're not using Express, that value won't necessarily be set, so you have two options:
// Set the header based on conditions
app.use(helmet.hsts({
maxAge: 1234000,
setIf: function(req, res) {
return Math.random() < 0.5;
}
}));
// ALWAYS set the header
app.use(helmet.hsts({
maxAge: 1234000,
force: true
}));
Note that the max age is in milliseconds, even though the spec uses seconds. This will round to the nearest full second.
Limitations: This only works if your site actually has HTTPS. It won't tell users on HTTP to switch to HTTPS, it will just tell HTTPS users to stick around. You can enforce this with the express-enforces-ssl module. It's somewhat well-supported by browsers.
Trying to prevent: Hackers can exploit known vulnerabilities in Express/Node if they see that your site is powered by Express (or whichever framework you use). X-Powered-By: Express
is sent in every HTTP request coming from Express, by default.
How to use Helmet to mitigate this: The hidePoweredBy
middleware will remove the X-Powered-By
header if it is set (which it will be by default in Express).
app.use(helmet.hidePoweredBy());
You can also explicitly set the header to something else, if you want. This could throw people off:
app.use(helmet.hidePoweredBy({ setTo: 'PHP 4.2.0' }));
Note: if you're using Express, you can skip Helmet's middleware if you want:
app.disable('x-powered-by');
Limitations: There might be other telltale signs that your site is Express-based (a blog post about your tech stack, for example). This might prevent hackers from easily exploiting known vulnerabilities in your stack, but that's all it does.
Trying to prevent: Some web applications will serve untrusted HTML for download. By default, some versions of IE will allow you to open those HTML files in the context of your site, which means that an untrusted HTML page could start doing bad things in the context of your pages. For more, see this MSDN blog post.
How to use Helmet to mitigate this: Set the X-Download-Options
header to noopen
to prevent IE users from executing downloads in your site's context.
app.use(helmet.ienoopen());
Limitations: This is pretty obscure, fixing a small bug on IE only. No real drawbacks other than performance/bandwidth of setting the headers, though.
Trying to prevent: Some browsers will try to "sniff" mimetypes. For example, if my server serves file.txt with a text/plain content-type, some browsers can still run that file with <script src="file.txt"></script>
. Many browsers will allow file.js to be run even if the content-type isn't for JavaScript. There are some other vulnerabilities, too.
How to use Helmet to mitigate this: Use Helmet's nosniff
middleware to keep Chrome, Opera, and IE from doing this sniffing (and Firefox soon). The following example sets the X-Content-Type-Options
header to its only option, nosniff
:
app.use(helmet.nosniff());
MSDN has a good description of how browsers behave when this header is sent.
Limitations: This only prevents against a certain kind of attack.
Trying to prevent: Users caching your old, buggy resources. It's possible that you've got bugs in an old HTML or JavaScript file, and with a cache, some users will be stuck with those old versions.
How to use Helmet to mitigate this: Use Helmet to disable this kind of caching. This sets a number of HTTP headers that stop caching.
app.use(helmet.nocache());
This will set Cache-Control
and Pragma
headers to stop caching. It will also set an Expires
header of 0, effectively saying "this has already expired."
If you want to crush the ETag
header as well, you can:
app.use(helmet.nocache({ noEtag: true }));
Limitations: Caching has some real benefits, and you lose them here. Browsers won't cache resources with this enabled, although some performance is retained if you keep ETag support. It's also possible that you'll introduce new bugs and you'll wish people had old resources cached, but that's less likely.
Trying to prevent: Adobe defines the spec for crossdomain.xml, a policy file that grants some Adobe products (like Flash) read access to resources on your domain. An unrestrictive policy could let others load things off your domain that you don't want.
How to use Helmet to mitigate this: Simply use Helmet's crossdomain
middleware to serve up a restrictive policy:
app.use(helmet.crossdomain());
This serves the policy at /crossdomain.xml
. By default, this is case-insensitive. To make it case-sensitive:
app.use(helmet.crossdomain({ caseSensitive: true }));
// This will now ONLY match all-lowercase /crossdomain.xml.
Limitations: This doesn't make you wildly more secure, but it does help to keep Flash from loading things that you don't want it to. You might also want some of this behavior, in which case you should make your own less-restrictive policy and serve it.
FAQs
help secure Express/Connect apps with various HTTP headers
We found that helmet demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.
Security News
A Stanford study reveals 9.5% of engineers contribute almost nothing, costing tech $90B annually, with remote work fueling the rise of "ghost engineers."
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.